// ------------------------------------------------------------------------
// 项目名称：Canroc.Net
// 版权归属：Canroc（https://gitee.com/canroc）
// 
// 许可证信息
// Canroc.Net项目主要遵循 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-APACHE 文件。
// 
// 使用条款：
// 1.使用本项目应遵守相关法律法规和许可证的要求。
// 2.不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动。
// 3.任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Canroc.Net 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// ------------------------------------------------------------------------

using Canroc.Net.Core.Enum;
using Canroc.Net.Core.Model;
using Canroc.Net.Event.system.SysMailEvent.Dto;
using Canroc.Net.WebSocket.Clients;
using Canroc.Net.WebSocket.Hubs;
using Microsoft.AspNetCore.SignalR;

namespace Canroc.Net.Event.System.SysMailEvent;

public class SysMailEventSubscriber(IServiceScopeFactory serviceScopeFactory) : IEventSubscriber, ISingleton
{
    /// <summary>
    ///     站内信推送事件
    /// </summary>
    /// <returns></returns>
    [EventSubscribe(EventTopicConst.SysSentMail)]
    public async Task MessagePushAsync(EventHandlerExecutingContext context)
    {
        if (context.Source.Payload is not MailSentPayloadInput payload)
            throw Oops.Oh("无效载荷，无法继续处理！").WithData(context.Source.Payload);

        using var scope = serviceScopeFactory.CreateScope();

        // 发布站内信
        List<Guid> allUserIds;
        switch (payload.SendingRange)
        {
            case MailSendingRangeEnum.AllUser:
                var userRep = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<SysUser>>();
                allUserIds = await userRep.AsQueryable().Where(u => u.IsEnable).Select(u => u.Id).ToListAsync();
                break;
            case MailSendingRangeEnum.AppointOrg:
                var orgAndUserRep = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<RelOrgUser>>();
                allUserIds = await orgAndUserRep.AsQueryable().Where(u => u.OrgId == payload.OrgId)
                    .Select(iou => iou.UserId).ToListAsync();
                break;
            case MailSendingRangeEnum.AppointRole:
                var roleAndUserRep = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<RelRoleUser>>();
                allUserIds = await roleAndUserRep.AsQueryable().Where(u => payload.RoleIds!.Contains(u.RoleId))
                    .Select(iou => iou.UserId)
                    .ToListAsync();
                break;
            case MailSendingRangeEnum.AppointUser:
                allUserIds = payload.UserIds!;
                break;
            default:
                throw Oops.Oh("发送范围错误");
        }

        var mailAndUserRep = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<RelMailUser>>();
        // 插入站内信和用户关联
        var mailAndUsers = allUserIds.Select(u => new RelMailUser { MailId = payload.MailId, UserId = u })
            .ToList();
        _ = await mailAndUserRep.InsertRangeAsync(mailAndUsers);

        // 推送站内信
        var mailRep = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<SysMail>>();
        var mail = await mailRep.GetFirstAsync(m => m.Id == payload.MailId);
        if (mail is null)
            throw Oops.Oh("站内信不存在").WithData(payload.MailId);
        var mailHub = scope.ServiceProvider.GetRequiredService<IHubContext<MailListenInHub, IMailListenInClient>>();
        if (payload.SendingRange == MailSendingRangeEnum.AllUser)
        {
            // 向所有在线的用户推送消息
            await mailHub.Clients.All.ReceiveMessage(new MailShortModel
            {
                Id = mail.Id,
                MailType = mail.MailType,
                Title = mail.Title,
                CreateUserName = mail.CreateUserName,
                CreateTime = mail.CreateTime
            });
        }
        else
        {
            // 向指定的用户推送消息
            var clientUserIds = allUserIds.Select(u => u.ToString("N"));
            await mailHub.Clients.Users(clientUserIds).ReceiveMessage(new MailShortModel
            {
                Id = mail.Id,
                MailType = mail.MailType,
                Title = mail.Title,
                CreateUserName = mail.CreateUserName,
                CreateTime = mail.CreateTime
            });
        }
    }

    /// <summary>
    ///     站内信撤回事件
    /// </summary>
    /// <returns></returns>
    [EventSubscribe(EventTopicConst.SysWithdrawMail)]
    public async Task WithdrawMessageAsync(EventHandlerExecutingContext context)
    {
        if (context.Source.Payload is not MailWithdrawPayloadInput payload)
            throw Oops.Oh("无效载荷，无法继续处理！").WithData(context.Source.Payload);

        // 撤销站内信的发布
        using var scope = serviceScopeFactory.CreateScope();
        var mailAndUserRep = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<RelMailUser>>();
        _ = await mailAndUserRep.DeleteAsync(imu => imu.MailId == payload.MailId);
    }
}